
import { Particle } from "./canvasparticle"
import { WindField } from "./canvaswindfield"
import * as Cesium from "cesium";

const PARTICLES_NUMBER = 2000;
const SPEED_RATE = 0.2;
const MAX_AGE = 10;
const BRIGHTEN = 2.5;

class Windy {
  constructor(windData, cesiumViewer) {
    this.windData = windData;
    this.windField = null;
    this.particles = [];
    this.lines = null;
    this._primitives = cesiumViewer.scene.primitives;
    this._init();
  }

  _init() {
    this.windField = this.createField();
    for (let i = 0; i < PARTICLES_NUMBER; i++) {
      this.particles.push(this.randomParticle(new Particle()));
    }
  }

  createField() {
    const data = this._parseWindJson();
    return new WindField(data);
  }

  animate() {
    const self = this;
    const field = self.windField;
    const particles = self.particles;

    const instances = [];
    let nextX = null;
    let nextY = null;
    let xy = null;
    let uv = null;
    particles.forEach(function (particle) {
      if (particle.age <= 0) {
        self.randomParticle(particle);
      }
      if (particle.age > 0) {
        const x = particle.x;
        const y = particle.y;

        if (!field.isInBound(x, y)) {
          particle.age = 0;
        } else {
          uv = field.getIn(x, y);
          nextX = x + SPEED_RATE * uv[0];
          nextY = y + SPEED_RATE * uv[1];
          particle.path.push(nextX, nextY);
          particle.x = nextX;
          particle.y = nextY;
          instances.push(self._createLineInstance(self._map(particle.path), particle.age / particle.birthAge));
          particle.age--;
        }
      }
    });
    if (instances.length <= 0) this.removeLines();
    self._drawLines(instances);
  }

  _parseWindJson() {
    let uComponent = null;
    let vComponent = null;
    let header = null;
    this.windData.forEach(function (record) {
      const type = record.header.parameterCategory + "," + record.header.parameterNumber;
      switch (type) {
        case "2,2":
          uComponent = record['data'];
          header = record['header'];
          break;
        case "2,3":
          vComponent = record['data'];
          break;
        default:
          break;
      }
    });
    return {
      header: header,
      uComponent: uComponent,
      vComponent: vComponent
    };
  }

  removeLines() {
    if (this.lines) {
      this._primitives.remove(this.lines);
      // this.lines.destroy();
    }
  }

  _map(arr) {
    const length = arr.length;
    const field = this.windField;
    const dx = field.dx;
    const dy = field.dy;
    const west = field.west;
    const south = field.north;
    const newArr = [];
    for (let i = 0; i <= length - 2; i += 2) {
      newArr.push(
        west + arr[i] * dx,
        south - arr[i + 1] * dy
      );
    }
    return newArr;
  }

  _createLineInstance(positions, ageRate) {
    const colors = [];
    const length = positions.length;
    const count = length / 2;
    for (let i = 0; i < length; i++) {
      colors.push(Cesium.Color.WHITE.withAlpha(i / count * ageRate * BRIGHTEN));
    }
    return new Cesium.GeometryInstance({
      geometry: new Cesium.PolylineGeometry({
        positions: Cesium.Cartesian3.fromDegreesArray(positions),
        colors: colors,
        width: 2.0,
        vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT
      })
    });
  }

  _drawLines(instances) {
    this.removeLines();
    this.lines = this._primitives.add(new Cesium.Primitive({
      geometryInstances: instances,
      appearance: new Cesium.PolylineColorAppearance()
    }));
  }

  randomParticle(particle) {
    let x, y;
    let safe = 0;
    do {
      x = Math.floor(Math.random() * (this.windField.cols - 2));
      y = Math.floor(Math.random() * (this.windField.rows - 2));
    } while (this.windField.getIn(x, y)[2] <= 0 && safe++ < 30);

    particle.x = x;
    particle.y = y;
    particle.age = Math.round(Math.random() * MAX_AGE);
    particle.birthAge = particle.age;
    particle.path = [x, y];
    return particle;
  }
}

export default Windy;
